#pragma once

#include <algorithm>


namespace evm { namespace algo {

template <typename Container, typename T>
bool find(const Container& c, const T& val) {
    return std::find(c.cbegin(), c.cend(), val) != c.cend();
};

template <typename T, typename E>
bool in(const T& val, std::initializer_list<E> range) {
    for (auto& item: range) {
        if (val == item)
            return true;
    }

    return false;
}

template <typename Container, typename UnaryPredicate>
bool all(const Container& c, UnaryPredicate p) {
    for (auto& item: c) {
        if (!p(item))
            return false;
    }
    return true;
};

template <typename Container, typename UnaryPredicate>
bool any(const Container& c, UnaryPredicate p) {
    for (auto& item: c) {
        if (p(item))
            return true;
    }
    return false;
};

template <typename Container, typename UnaryPredicate>
bool none(const Container& c, UnaryPredicate p) {
    for (auto& item: c) {
        if (p(item))
            return false;
    }
    return true;
};

template <typename Container>
typename Container::const_reference
max(const Container& c) {
    return *std::max_element(c.cbegin(), c.cend());
};

template <typename Container, typename Compare>
typename Container::const_reference
max(const Container& c, Compare cmp) {
    return *std::max_element(c.cbegin(), c.cend(), cmp);
};

template <typename Container>
typename Container::const_reference
min(const Container& c) {
    return *std::min_element(c.cbegin(), c.cend());
};

template <typename Container, typename Compare>
typename Container::const_reference
min(const Container& c, Compare cmp) {
    return *std::min_element(c.cbegin(), c.cend(), cmp);
};

template <typename Container>
std::pair<typename Container::const_reference, typename Container::const_reference>
minmax(const Container& c) {
    auto p = std::minmax_element(c.cbegin(), c.cend());
    return std::make_pair(*p.first, *p.second);
};

template <typename Container, typename Compare>
std::pair<typename Container::const_reference, typename Container::const_reference>
minmax(const Container& c, Compare cmp) {
    auto p = std::minmax_element(c.cbegin(), c.cend(), cmp);
    return std::make_pair(*p.first, *p.second);
};

template <typename Container>
void sort(Container& c) {
    std::sort(c.begin(), c.end());
}

template <typename Container, typename Compare>
void sort(Container& c, Compare cmp) {
    std::sort(c.begin(), c.end(), cmp);
}

template <typename Container, typename T>
T sum(const Container& c, T init = 0) {
    for (auto& item: c)
        init += item;
    return init;
}

template <typename Container, typename T, typename UnaryOperation>
T sum(const Container& c, T init, UnaryOperation op) {
    for (auto& item: c)
        init += op(item);
    return init;
}

}}
